home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 20 code / Scripting the Finder / Finder Snapshot / EventHandler.cp < prev    next >
Encoding:
Text File  |  1994-10-04  |  11.8 KB  |  489 lines  |  [TEXT/MMCC]

  1. /*================================================================================
  2.     EventHandler.c
  3.     
  4.     ©1991-4 Greg Anderson
  5.     greggor@apple.com
  6.         
  7.     This code handles the main macintosh event loop    
  8. ================================================================================*/
  9. #include <EPPC.h>
  10. #include <AppleEvents.h>
  11. #include <Errors.h>
  12.  
  13. #include "EventHandler.h"
  14. #include "NextEvent.h"
  15. // #include "MenuHandler.h"
  16. // #include "WindowHandler.h"
  17.  
  18. #include "Main.h"
  19.  
  20. #include "MacUtilities.h"
  21.  
  22. #ifndef Exceptions_h
  23. #include "Exceptions.h"
  24. #endif
  25.  
  26. //
  27. // Prototypes for private functions:
  28. //
  29. void Idle(EventRecord* nullEvent);
  30.  
  31. // void                    ProcessModelessDialog( EventRecord* theEvent  );
  32. // Boolean                ProcessMouseEvent( EventRecord* theEvent  );
  33. // void                    SetupCursorShape( Point theMouse, RgnHandle mouseRgn );
  34.  
  35. //----------------------------------------------------------------------------------------
  36. // Idle: 
  37. //----------------------------------------------------------------------------------------
  38. void Idle(EventRecord* nullEvent)
  39. {
  40.  
  41. } // Idle 
  42.  
  43. //----------------------------------------------------------------------------------------
  44. // HandleEvents: 
  45. //
  46. // Main event processor
  47. //----------------------------------------------------------------------------------------
  48. void HandleEvents( RgnHandle mouseRegion )
  49. {
  50.     EventRecord        theEvent;
  51.     Boolean            isDialogEvent;
  52.     long            theSleep;
  53.     Point            mouse;
  54.     char            keyPressed;
  55.     OSErr            err = noErr;
  56.     
  57.     //
  58.     // This routine watches the cursor as it moves across the
  59.     // window & changes its shape as necessary.
  60.     //
  61.     GetMouse( &mouse );
  62.     LocalToGlobal( &mouse );
  63.     // SetupCursorShape( mouse, mouseRegion);
  64.     
  65.     //
  66.     // Get the next event, whatever type it might be.
  67.     //
  68.     // 'NextEvent' calls either GetNextEvent or WaitNextEvent
  69.     // (preferably the later).  It does some processing
  70.     // to make deactivate, suspend, resume and mouse-moved
  71.     // events easier to interpret.
  72.     //
  73.     // If 'GetNextEvent' is called, mouse-moved events are
  74.     // simulated, so the same cursor-tracking code may be
  75.     // used in multifinder and non-multifinder environments.
  76.     //
  77.     theSleep = 10;
  78.     isDialogEvent = NextEvent( everyEvent, &theEvent, theSleep, mouseRegion );
  79.  
  80. #ifdef ShowMouseRgn
  81.     SetPort(gWindowMgrPort);
  82.     SetClip(gUniverseRgn);
  83.     InvertRgn(mouseRegion);
  84.     InvertRgn(mouseRegion);
  85. #endif
  86.  
  87.     //
  88.     // It seems that the only way to do accurate mouse tracking
  89.     // is to call SetupCursorShape before and after NextEvent.
  90.     //
  91.     // Passing nil as the mouseRgn prevents all of the complex region
  92.     // calculations from being done twice.
  93.     //
  94.     // SetupCursorShape( theEvent.where, nil );
  95.     
  96.     //
  97.     // Set up a failure handler for commands that just cannot be completed
  98.     //
  99.     Try
  100.     {
  101.         Boolean eventHandled = false;
  102.         
  103.         //
  104.         // Here is the dreaded Event Switch Statement.
  105.         //
  106.         // I should write a better event processor -- or better yet,
  107.         // switch to MacApp.  :>
  108.         //
  109.         // A word of warning for the unwary:  NextEvent() mauls
  110.         // theEvent.what, so some of the items in this switch statement
  111.         // might be undefined if GetNextEvent or WaitNextEvent is
  112.         // called directly.  Activate, deactivate, suspend and resume
  113.         // events are all mauled by NextEvent.  See NextEvent.c for
  114.         // code that detects these events (or better yet, include
  115.         // NextEvent.c in your project and use this code as a sample,
  116.         // and you'll be MultiFinder aware).
  117.         //
  118.         switch( theEvent.what )
  119.         {
  120.             //
  121.             // First check for high-level events (e.g. AppleEvents)
  122.             //
  123.             case kHighLevelEvent:
  124.             {
  125.                 AEProcessAppleEvent( &theEvent );
  126.                 eventHandled = true;
  127.                 break;
  128.             }
  129.             
  130.             //
  131.             // If the event is a mousedown event, theEvent.message is undefined,
  132.             // but theEvent.where specifies where the mouse was located when the
  133.             // button went down.
  134.             //
  135.             case mouseDown:    
  136.             {
  137. //                eventHandled = ProcessMouseEvent( &theEvent );
  138.                 break;
  139.             }
  140.             
  141.             //
  142.             // If the event is a keyDown or autoKey event, theEvent.message
  143.             // contains the character code & key code of the key pressed
  144.             // in its low word.
  145.             //
  146.             case autoKey:
  147.             {
  148.                 //
  149.                 // Don't allow autokeys to work with menu equivalents
  150.                 //
  151.                 if( (theEvent.modifiers & cmdKey) != 0 )
  152.                 {
  153.                     eventHandled = true;
  154.                     break;
  155.                 }
  156.             }
  157.             
  158.             case keyDown:
  159.             {
  160.                 keyPressed = (char)(theEvent.message & charCodeMask);
  161.                 
  162. #ifdef REMOVED
  163.                 //
  164.                 // Handle command-key equivalents of menu functions
  165.                 //
  166.                 if( (theEvent.modifiers & cmdKey) != 0)
  167.                 {
  168.                     SetupMenuItems();
  169.                     ProcessMenuSelection( MenuKey(keyPressed) );
  170.                     eventHandled = true;
  171.                 }
  172.                 else
  173.                 {
  174.                     eventHandled = FrontWindowHandler()->KeyDown(&theEvent, keyPressed);
  175.                 }
  176. #endif
  177.                 
  178.                 break;
  179.             }
  180.             
  181.             //
  182.             // If the event is an update event or an activate event,
  183.             // theEvent.message contains a pointer to the window 
  184.             // receiving the event
  185.             //
  186.             case updateEvt:
  187.             {
  188. #ifdef REMOVED
  189.                 GetWindowHandler((WindowPtr)(theEvent.message))->Update(&theEvent);
  190. #endif
  191.                 break;
  192.             }
  193.             
  194.             //
  195.             // An activate event can mean that a window is being activated,
  196.             // OR it could mean that a window is being deactivated.
  197.             //
  198.             // However, NextEvent decodes the event record and returns
  199.             // 'deactivateEvt' if the event was a deactivate; this
  200.             // simplifies this switch statement.  Be careful when copying
  201.             // this code--if you call WaitNextEvent directly, the
  202.             // translation will not be done and this code won't work.
  203.             //
  204.             case activateEvt:
  205.             {
  206. #ifdef REMOVED
  207.                 GetWindowHandler((WindowPtr)(theEvent.message))->Activate(&theEvent);
  208. #endif
  209.                 break;
  210.             }
  211.             
  212.             case deactivateEvt:
  213.             {
  214. #ifdef REMOVED
  215.                 GetWindowHandler((WindowPtr)(theEvent.message))->Deactivate(&theEvent);
  216. #endif
  217.                 break;
  218.             }
  219.             
  220.             //
  221.             // Suspend and resume events are treated like activate and
  222.             // deactivate messages.  (Note that FrontWindow() might
  223.             // return nil; ActivateWindow and DeactivateWindow should
  224.             // catch this and exit gracefully.)
  225.             //
  226.             // Note that NextEvent decodes app4Evt's and returns either
  227.             // resumeEvt, suspendEvt or mouseMovedEvt.
  228.             //
  229.             case resumeEvt:
  230.             {
  231. #ifdef REMOVED
  232.                 GetWindowHandler((WindowPtr)(theEvent.message))->Resume(&theEvent);
  233. #endif
  234.                 break;
  235.             }
  236.             
  237.             case suspendEvt:
  238.             {
  239. #ifdef REMOVED
  240.                 GetWindowHandler((WindowPtr)(theEvent.message))->Suspend(&theEvent);
  241. #endif
  242.                 break;
  243.             }
  244.             
  245.             //
  246.             // The mouseRegion is recalculated on every event,
  247.             // so nothing special needs to be done on mouseMovedEvt.
  248.             //
  249.             case mouseMovedEvt:
  250.             {
  251.                 break;
  252.             }
  253.         }
  254.  
  255. #ifdef REMOVED
  256.         //
  257.         // Check for modeless dialog events & pass them to the
  258.         // appropriate modeless dialog box.
  259.         //
  260.         // Do not pass events already handled above, though.
  261.         //
  262.         if( isDialogEvent && (eventHandled == false))
  263.         {
  264.             ProcessModelessDialog( &theEvent );
  265.         }
  266. #endif
  267.                 
  268.         //
  269.         // Do idle-type-stuff
  270.         //
  271.         Idle(&theEvent);
  272.     }
  273.     Catch(err)
  274.     {
  275. #ifdef REMOVED
  276.         if((err != eNoWindowHandler) && (err != eUserCanceled))
  277.         {
  278.             //
  279.             // It would be nice if we had better error reporting
  280.             //
  281.             ReportError( "\pThe command could not be completed", err );
  282.         }
  283. #endif
  284.     }
  285. } // HandleEvents 
  286.  
  287. #ifdef REMOVED
  288.  
  289. //----------------------------------------------------------------------------------------
  290. // ProcessModelessDialog: 
  291. //
  292. // Modeless-dialog event.
  293. //----------------------------------------------------------------------------------------
  294. void ProcessModelessDialog( EventRecord* theEvent  )
  295. {
  296.     DialogPtr            theDialog;
  297.     short                itemHit;
  298.  
  299.     //
  300.     // If the event is a modeless dialog event, pass it to
  301.     // DialogSelect.
  302.     //
  303.     // If DialogSelect returns 'true', that indicates that
  304.     // the user has interacted with the dialog in some way.
  305.     // If this is the case, theDialog will point to the
  306.     // dialog box in question, and itemHit will contain the
  307.     // number of the item clicked on.
  308.     //
  309.     // We determine which dialog was clicked on by examining
  310.     // a field in the record pointed to by the dialog's
  311.     // refCon.
  312.     //
  313.     if( DialogSelect( theEvent, &theDialog, &itemHit ) )
  314.     {
  315.         //
  316.         // Pass the event record and itemHit to the window handler
  317.         //
  318.         GetWindowHandler(theDialog)->DialogManagerEvent(theEvent, itemHit);
  319.     }
  320. } // ProcessModelessDialog 
  321.  
  322. //----------------------------------------------------------------------------------------
  323. // ProcessMouseEvent: 
  324. //
  325. // Mouse-click event.
  326. //
  327. // Strangely enough, theEvent->message doesn't tell us which window
  328. // was clicked on.  The Macintosh toolbox function 'FindWindow' can
  329. // determine this for us, however.
  330. //----------------------------------------------------------------------------------------
  331. Boolean ProcessMouseEvent( EventRecord* theEvent  )
  332. {
  333.     WindowPtr    whichWindow;
  334.     Boolean        eventHandled = false;
  335.     
  336.     switch( FindWindow( theEvent->where, &whichWindow ) )
  337.     {
  338.         case inMenuBar:
  339.         {
  340.             SetupMenuItems();
  341.             ProcessMenuSelection( MenuSelect(theEvent->where) );
  342.             eventHandled = true;
  343.             break;
  344.         }
  345.         
  346.         case inSysWindow:
  347.         {
  348.             SystemClick( theEvent,(WindowPtr)whichWindow );
  349.             eventHandled = true;
  350.             break;
  351.         }
  352.         
  353.         case inContent:
  354.         {
  355.             //
  356.             // If the window clicked on is not frontmost, make it frontmost.
  357.             //
  358.             if( whichWindow != FrontWindow() )
  359.             {
  360.                 SelectWindow(whichWindow);
  361.                 eventHandled = true;
  362.             }
  363.             else
  364.             {
  365.                 eventHandled = GetWindowHandler(whichWindow)->ContentClick(theEvent);
  366.             }
  367.             break;
  368.         }
  369.         
  370.         case inDrag:
  371.         {
  372.             DragWindow( (WindowPtr)whichWindow,theEvent->where,&gUniverseRect);
  373.             eventHandled = true;
  374.             break;
  375.         }
  376.             
  377.         case inGrow:
  378.         {
  379.             GetWindowHandler(whichWindow)->ResizeWindow(theEvent->where);
  380.             eventHandled = true;
  381.             break;
  382.         }
  383.         
  384.         case inGoAway:
  385.         {
  386.             if( TrackGoAway(whichWindow,theEvent->where) )
  387.             {
  388.                 //
  389.                 // We only have one window, so close it
  390.                 //
  391.                 GetWindowHandler(whichWindow)->CloseWindowByUser();
  392.             }
  393.             eventHandled = true;
  394.             break;
  395.         }
  396.     }
  397.     return eventHandled;
  398. } // ProcessMouseEvent 
  399.  
  400. //----------------------------------------------------------------------------------------
  401. // SetupCursorShape: 
  402. //
  403. // Change the shape of the cursor based on its location
  404. //----------------------------------------------------------------------------------------
  405. void SetupCursorShape( Point theMouse, RgnHandle mouseRgn )
  406. {
  407.     OSErr err = noErr;
  408.             
  409.     //
  410.     // Try to set the shape of the cursor
  411.     //
  412.     Try
  413.     {
  414.         WindowPtr inWindow = nil;
  415.         Rect tRect;
  416.         Rect windowRect;
  417.         
  418.         //
  419.         // Is there a window?  If not, fail (error code is ignored, so it
  420.         // doesn't matter what it is)
  421.         //
  422.         inWindow = FrontWindow();
  423.         if(inWindow == nil)
  424.             Throw(-1);
  425.         
  426.         SetPort(inWindow);
  427.         GetGlobalWindowLocation(inWindow, &windowRect);    // inWindow->port.portRect
  428.                 
  429.         //
  430.         // If the point is not inside the front window,
  431.         // then set the cursor to an arrow, and set the mouse
  432.         // region to the universe minus the space taken by
  433.         // the front window
  434.         //
  435.         if(PtInRect(theMouse, &windowRect) == false)
  436.         {
  437.             ChangeCursor(0);
  438.             if(mouseRgn != nil)
  439.             {
  440.                 RectRgn(mouseRgn, &windowRect);
  441.                 XorRgn(mouseRgn, gUniverseRgn, mouseRgn);
  442.             }
  443.         }
  444.         else
  445.         {
  446.             //
  447.             // Do all of our work in local coordinates
  448.             //
  449.             GlobalToLocal(&theMouse);    
  450.  
  451.             //
  452.             // By default, the mouse region is a one-pixel region
  453.             // that just surrounds the cursor.  TWindowHandler::SetupCursorShape
  454.             // may change this region to something else
  455.             //
  456.             SetRect(&tRect, theMouse.h, theMouse.v, theMouse.h + 1, theMouse.v + 1);
  457.             if(mouseRgn != nil)
  458.                 RectRgn(mouseRgn, &tRect);
  459.  
  460.             //
  461.             // If this window doesn't have a window handler, then
  462.             // GetWindowHandler will fail.  If SetupCursorShape
  463.             // returns false, then the handler did not have a specific
  464.             // shape to set the cursor to; set it to an arrow.
  465.             //            
  466.             if(GetWindowHandler(inWindow)->SetupCursorShape(theMouse, mouseRgn) == false)
  467.                 ChangeCursor(0);
  468.             
  469.             //
  470.             // Translate the region back to global coordinates
  471.             //
  472.             if(mouseRgn != nil)
  473.                 RgnToGlobal(mouseRgn);
  474.         }
  475.     }
  476.     Catch(err)
  477.     {
  478.         //
  479.         // If we couldn't handle the SetupCursorShape event, then
  480.         // the cursor is an arrow everywhere
  481.         //
  482.         ChangeCursor(0);
  483.         if(mouseRgn != nil)
  484.             RectRgn(mouseRgn, &gUniverseRect);
  485.     }
  486. } // SetupCursorShape 
  487.  
  488. #endif
  489.